Add support for deleting refs
authorColin Walters <walters@verbum.org>
Mon, 1 Jul 2013 14:18:26 +0000 (10:18 -0400)
committerColin Walters <walters@verbum.org>
Mon, 1 Jul 2013 19:41:27 +0000 (15:41 -0400)
The internal API will be used by admin, and "ostree refs --delete"
is handy for interactive management.

src/libostree/ostree-repo.c
src/ostree/ot-builtin-refs.c
tests/libtest.sh
tests/t0000-basic.sh

index 5ef94bfda6b9132827d4a146f8ccd65b180e0895..d53e4c64930a3eec5fb2db57dc9610d3aa3c9fb4 100644 (file)
@@ -1757,6 +1757,42 @@ create_empty_gvariant_dict (void)
   return g_variant_builder_end (&builder);
 }
 
+static gboolean
+add_ref_to_set (const char       *remote,
+                GFile            *base,
+                GFile            *child,
+                GHashTable       *refs,
+                GCancellable     *cancellable,
+                GError          **error)
+{
+  gboolean ret = FALSE;
+  char *contents;
+  char *relpath;
+  gsize len;
+  GString *refname;
+
+  if (!g_file_load_contents (child, cancellable, &contents, &len, NULL, error))
+    goto out;
+
+  g_strchomp (contents);
+
+  refname = g_string_new ("");
+  if (remote)
+    {
+      g_string_append (refname, remote);
+      g_string_append_c (refname, ':');
+    }
+  relpath = g_file_get_relative_path (base, child);
+  g_string_append (refname, relpath);
+  g_free (relpath);
+          
+  g_hash_table_insert (refs, g_string_free (refname, FALSE), contents);
+
+  ret = TRUE;
+ out:
+  return ret;
+}
+
 static gboolean
 enumerate_refs_recurse (OstreeRepo    *repo,
                         const char    *remote,
@@ -1793,27 +1829,9 @@ enumerate_refs_recurse (OstreeRepo    *repo,
         }
       else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
         {
-          char *contents;
-          char *relpath;
-          gsize len;
-          GString *refname;
-
-          if (!g_file_load_contents (child, cancellable, &contents, &len, NULL, error))
+          if (!add_ref_to_set (remote, base, child, refs,
+                               cancellable, error))
             goto out;
-
-          g_strchomp (contents);
-
-          refname = g_string_new ("");
-          if (remote)
-            {
-              g_string_append (refname, remote);
-              g_string_append_c (refname, ':');
-            }
-          relpath = g_file_get_relative_path (base, child);
-          g_string_append (refname, relpath);
-          g_free (relpath);
-          
-          g_hash_table_insert (refs, g_string_free (refname, FALSE), contents);
         }
     }
 
@@ -1840,6 +1858,7 @@ ostree_repo_list_refs (OstreeRepo       *repo,
     {
       gs_unref_object GFile *dir = NULL;
       gs_unref_object GFile *child = NULL;
+      gs_unref_object GFileInfo *info = NULL;
 
       if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error))
         goto out;
@@ -1850,11 +1869,26 @@ ostree_repo_list_refs (OstreeRepo       *repo,
         dir = g_object_ref (repo->local_heads_dir);
 
       child = g_file_resolve_relative_path (dir, ref_prefix);
+      if (!ot_gfile_query_info_allow_noent (child, OSTREE_GIO_FAST_QUERYINFO, 0,
+                                            &info, cancellable, error))
+        goto out;
 
-      if (!enumerate_refs_recurse (repo, remote, child, child,
-                                   ret_all_refs,
+      if (info)
+        {
+          if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
+            {
+              if (!enumerate_refs_recurse (repo, remote, child, child,
+                                           ret_all_refs,
+                                           cancellable, error))
+                goto out;
+            }
+          else
+            {
+              if (!add_ref_to_set (remote, dir, child, ret_all_refs,
                                    cancellable, error))
-        goto out;
+                goto out;
+            }
+        }
     }
   else
     {
@@ -1954,19 +1988,38 @@ ostree_repo_write_ref (OstreeRepo  *self,
   else
     {
       dir = g_file_get_child (self->remote_heads_dir, remote);
-
-      if (!gs_file_ensure_directory (dir, FALSE, NULL, error))
-        goto out;
+      
+      if (rev != NULL)
+        {
+          if (!gs_file_ensure_directory (dir, FALSE, NULL, error))
+            goto out;
+        }
     }
 
-  if (!write_checksum_file (dir, name, rev, error))
-    goto out;
-
-  if (self->mode == OSTREE_REPO_MODE_ARCHIVE
-      || self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2)
+  if (rev == NULL)
     {
-      if (!write_ref_summary (self, NULL, error))
+      gs_unref_object GFile *child = g_file_resolve_relative_path (dir, name);
+      
+      if (g_file_query_exists (child, NULL))
+        {
+          if (!gs_file_unlink (child, NULL, error))
+            goto out;
+        }
+    }
+  else
+    {
+      if (!write_checksum_file (dir, name, rev, error))
         goto out;
+      
+      if (rev != NULL)
+        {
+          if (self->mode == OSTREE_REPO_MODE_ARCHIVE
+              || self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2)
+            {
+              if (!write_ref_summary (self, NULL, error))
+                goto out;
+            }
+        }
     }
 
   ret = TRUE;
index 541d959b0f60277af8b41d91f7d1ebdfb2fe6fd9..3164604deb7b30a415156b5b100417dd5c0022b7 100644 (file)
 #include "ostree.h"
 #include "ostree-repo-file.h"
 
+static gboolean opt_delete;
+
 static GOptionEntry options[] = {
+  { "delete", 0, 0, G_OPTION_ARG_NONE, &opt_delete, "Delete refs which match PREFIX, rather than listing them", "PREFIX" },
   { NULL }
 };
 
@@ -41,9 +44,8 @@ ostree_builtin_refs (int argc, char **argv, GFile *repo_path, GError **error)
   gs_unref_hashtable GHashTable *refs = NULL;
   GHashTableIter hashiter;
   gpointer hashkey, hashvalue;
-  guint i;
 
-  context = g_option_context_new ("[PREFIX...] - List refs");
+  context = g_option_context_new ("[PREFIX] - List refs");
   g_option_context_add_main_entries (context, options, NULL);
 
   if (!g_option_context_parse (context, &argc, &argv, error))
@@ -60,11 +62,24 @@ ostree_builtin_refs (int argc, char **argv, GFile *repo_path, GError **error)
                               cancellable, error))
     goto out;
 
-  g_hash_table_iter_init (&hashiter, refs);
-  while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
+  if (!opt_delete)
+    {
+      g_hash_table_iter_init (&hashiter, refs);
+      while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
+        {
+          const char *ref = hashkey;
+          g_print ("%s\n", ref);
+        }
+    }
+  else
     {
-      const char *ref = hashkey;
-      g_print ("%s\n", ref);
+      g_hash_table_iter_init (&hashiter, refs);
+      while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
+        {
+          const char *refspec = hashkey;
+          if (!ostree_repo_write_refspec (repo, refspec, NULL, error))
+            goto out;
+        }
     }
  
   ret = TRUE;
index e4518f1f10b95c13d9696240ca4e02dea99b5f3b..12ddd64602c4db5c9f0eb4c771bbdce3ed55e7b2 100644 (file)
@@ -44,6 +44,12 @@ assert_not_has_file () {
     fi
 }
 
+assert_not_file_has_content () {
+    if grep -q -e "$2" "$1"; then
+       echo 1>&2 "File '$1' incorrectly matches regexp '$2'"; exit 1
+    fi
+}
+
 assert_file_has_content () {
     if ! grep -q -e "$2" "$1"; then
        echo 1>&2 "File '$1' doesn't match regexp '$2'"; exit 1
index 97bd7ed313b016704613d846f19699a1895c22db..a58a1fd73d50cb7f7ea4f4610f42e2a8a68fdb20 100755 (executable)
@@ -19,7 +19,7 @@
 
 set -e
 
-echo "1..33"
+echo "1..34"
 
 . $(dirname $0)/libtest.sh
 
@@ -244,3 +244,13 @@ fi
 rm repo3 objlist-before-prune objlist-after-prune -rf
 echo "ok prune"
 
+cd ${test_tmpdir}
+$OSTREE commit -b test3 -s "Another commit" --tree=ref=test2
+ostree --repo=repo refs > reflist
+assert_file_has_content reflist '^test3$'
+ostree --repo=repo refs --delete test3
+ostree --repo=repo refs > reflist
+assert_not_file_has_content reflist '^test3$'
+echo "ok reflist --delete"
+
+